/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.healthecology.processor;

import com.huawei.healthecology.api.HttpClient;
import com.huawei.healthecology.data.http.HttpResponseCallback;
import com.huawei.healthecology.data.http.HttpResponseCode;
import com.huawei.healthecology.data.http.HttpResponseData;
import com.huawei.healthecology.data.http.KitHttpRequest;
import com.huawei.healthecology.data.utils.CallbackProvider;
import com.huawei.healthecology.json.JsonMapper;

import lombok.Builder;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.Optional;

/**
 * The processor for http client
 */
@Builder
public class HttpClientProcessor implements HttpClient, HealthEcologyProcessor {
    private static final String EMPTY_RESPONSE_BODY = "Empty http result";

    private final OkHttpClient httpClient;

    private final JsonMapper jsonMapper;

    private CallbackProvider<HttpResponseCallback> callbackCallbackProvider;

    @Override
    public void initProcessor() {
    }

    @Override
    public void releaseResource() {
        Optional.ofNullable(callbackCallbackProvider).ifPresent(CallbackProvider::clear);
    }

    @Override
    public void destroyProcessor() {
        callbackCallbackProvider = null;
    }

    @Override
    public HttpResponseCode onHttpResponse(HttpResponseCallback responseCallback) {
        callbackCallbackProvider = Optional.ofNullable(callbackCallbackProvider)
            .map(provider -> provider.add(responseCallback))
            .orElse(CallbackProvider.<HttpResponseCallback>builder().callback(responseCallback).build());
        return HttpResponseCode.OPERATION_SUCCESS;
    }

    @Override
    public HttpResponseCode processHttpRequest(@NotNull KitHttpRequest httpRequest) {
        Headers.Builder headerBuilder = new Headers.Builder();
        Optional.ofNullable(httpRequest.getRequestHeaders())
            .flatMap(jsonMapper::getJsonMap)
            .ifPresent(map -> map.forEach(headerBuilder::add));
        Request.Builder requestBuilder = new Request.Builder()
            .headers(headerBuilder.build())
            .url(httpRequest.getHttpUrl());
        return httpRequest.getRequestType()
            .buildRequest(httpRequest.getRequestData(), requestBuilder)
            .map(validRequest -> {
                HttpResponseCallback responseCallback = Optional.ofNullable(callbackCallbackProvider)
                    .flatMap(CallbackProvider::getLast)
                    .orElse(null);
                Optional.ofNullable(responseCallback)
                    .ifPresent(callback -> processRequest(validRequest, callback));
                return HttpResponseCode.OPERATION_SUCCESS;
            })
            .orElse(HttpResponseCode.OPERATION_FAILED);
    }

    private void processRequest(Request request, HttpResponseCallback callback) {
        try (Response response = httpClient.newCall(request).execute()) {
            String resultBody = (response.body() != null)
                ? response.body().string()
                : EMPTY_RESPONSE_BODY;
            Optional.of(resultBody).ifPresent(data ->
                callback.onResponse(HttpResponseData.builder().responseData(data).build()));
        } catch (IOException e) {
            callback.onResponse(HttpResponseData.builder().errorMessage(e.getMessage()).build());
        }
    }
}
